import * as vscode from 'vscode';
import { ITypeScriptServiceClient } from '../../typescriptService';
import { Command, CommandManager } from '../../utils/commandManager';
import { ConfigurationDependentRegistration } from '../../utils/dependentRegistration';

import * as typeConverters from '../../utils/typeConverters';
import { NotDictNodeRequestArgs, DictInfo } from 'ctsscript/lib/protocol';

import { _指令类型_, 启动指令_, 分部完成参数_, 翻译请求参数_, 词典语句正则, 词典头正则, _词典完成项目种类_, 标识符_ } from './ctsEnumsAndTypes/enumsAndTypes';
import { 翻译标识符 } from './ctsTranslate/translateIdentifier';
import { 文本全为下划线, 文本全为大写或下划线, 字符是大写, 删除前缀, 取分部输出词典译文, 取分部输出词典原文及译文 } from './ctsUtils/utils';
import { 插入分部完成文本命令_ } from './ctsCommands/insertSegmentCompletionCommand';
import { 格式化词典语句命令_ } from './ctsCommands/formatDictCommand';
import { 插入词典标识符命令_ } from './ctsCommands/insertDictIdentifierCommand';


function 创建指令<T>(指令: _指令类型_, 参数?: T): 启动指令_<T> {
    return { 指令类型: 指令, 参数 };
}

function 创建分割符(序号: number) {
    return new 词典完成项目_(vscode.CompletionItemKind.File, _词典完成项目种类_.分隔符, undefined!, undefined!, 序号);
}
function 创建格式化及重新开始标签(序号: number) {
    return new vscode.CompletionList(创建格式化及重新开始项目(序号));
}

function 创建格式化及重新开始项目(序号: number) {
    let a = new 词典完成项目_(vscode.CompletionItemKind.Function, _词典完成项目种类_.格式化词典语句, "格式化词典", undefined!, 序号);
    let b = new 词典完成项目_(vscode.CompletionItemKind.Function, _词典完成项目种类_.重新开始, "重新开始", undefined!, 序号++);
    return [a, b];
}

export class 词典完成项目_ extends vscode.CompletionItem {
    撤销文本: string = "";
    标识符!: 标识符_;
    constructor(kind: vscode.CompletionItemKind, public 种类: _词典完成项目种类_, 标签: string, 是文本字面量?: boolean, 排序文本?: string | number, 撤销文本?: string, 前缀 = "", 后缀 = "", 标识符?: 标识符_) {
        super(前缀 + 标签 + 后缀, kind);
        this.sortText = 排序文本 + "";
        switch (种类) {
            case _词典完成项目种类_.分隔符:
                this.label = "----------------------> *** <----------------------";
                this.insertText = "";
                this.preselect = false;
                break
            case _词典完成项目种类_.标识符:
                this.insertText = 是文本字面量 ? `"${标签}":` : 标签 + ":";
                this.preselect = true;
                break;
            case _词典完成项目种类_.整体词组:
                this.insertText = 是文本字面量 ? `"${前缀 + 标签 + 后缀}",` : 前缀 + 标签 + 后缀 + ",";
                this.preselect = true;
                break;
            case _词典完成项目种类_.分体词组:
                this.insertText = "";
                this.command = {
                    title: "",
                    command: 插入分部完成文本命令_.ID,
                    arguments: [标签]
                }
                this.标识符 = 标识符!;
                break;
            case _词典完成项目种类_.忽略当前:
                this.insertText = "";
                this.撤销文本 = 撤销文本!;
                break;
            case _词典完成项目种类_.格式化词典语句:
            case _词典完成项目种类_.完成当前:
            case _词典完成项目种类_.重新开始:
                this.insertText = "";
                this.command = {
                    title: "",
                    command: 格式化词典语句命令_.ID
                }
                break;
        }
    }
}

class DictCompletionAcceptedCommand implements Command {
    public static readonly ID = '_ctsscript.onDictCompletionAccepted';
    public readonly ID = DictCompletionAcceptedCommand.ID;

    public constructor(
        private readonly onCompletionAccepted: (item: vscode.CompletionItem) => void
    ) { }

    public execute(item: vscode.CompletionItem) {
        this.onCompletionAccepted(item);
    }
}

class CtsScriptDictCompletionItemProvider implements vscode.CompletionItemProvider {

    public static readonly triggerCharacters = [' '];
    public 上个指令字符: string = undefined!;
    public 上次请求文本: string = undefined!;
    public 上个请求: DictInfo = undefined!;
    public 刚输入的完成项目: 词典完成项目_ = undefined!;
    public 储存的上组项目: 词典完成项目_[][] = undefined!;
    public 分部输出内容: string = "";

    constructor(
        private readonly client: ITypeScriptServiceClient,
        commandManager: CommandManager,
        onCompletionAccepted: (item: vscode.CompletionItem) => void
    ) {
        commandManager.register(new 格式化词典语句命令_(client));
        commandManager.register(new 插入分部完成文本命令_());
        commandManager.register(new 插入词典标识符命令_());
        commandManager.register(new DictCompletionAcceptedCommand(onCompletionAccepted));
    }

    public async provideCompletionItems(
        document: vscode.TextDocument,
        position: vscode.Position,
        token: vscode.CancellationToken,
        context: vscode.CompletionContext
    ): Promise<vscode.CompletionList | undefined> {
        let 指令 = this.生成请求参数(context, document, position);
        if (!指令) {
            return undefined;
        }
        switch (指令.指令类型) {
            case _指令类型_.全新开始: {
                const 结果 = await this.请求语言服务功能(指令.参数 as NotDictNodeRequestArgs, token);
                if (!结果) {
                    return 创建格式化及重新开始标签(1);
                }
                let a = new 词典完成项目_(vscode.CompletionItemKind.Enum, _词典完成项目种类_.标识符, 结果.body!.text!, 结果.body!.isInString, 1);
                let c = new 词典完成项目_(vscode.CompletionItemKind.Function, _词典完成项目种类_.忽略当前, "撤销: " + 结果.body!.text, undefined, 3, 结果.body!.text);
                this.上个请求 = 结果.body!;
                return new vscode.CompletionList([a, 创建分割符(2), c]);
            }
            case _指令类型_.再次开始: {
                const 结果 = await this.请求语言服务功能(指令.参数 as NotDictNodeRequestArgs, token);
                if (!结果) {
                    return 创建格式化及重新开始标签(1);
                }
                let a = new 词典完成项目_(vscode.CompletionItemKind.Enum, _词典完成项目种类_.标识符, 结果.body!.text!, 结果.body!.isInString, 1);
                let b = new 词典完成项目_(vscode.CompletionItemKind.Function, _词典完成项目种类_.忽略当前, "撤销: " + 结果.body!.text, undefined, 2, 结果.body!.text);
                this.上个请求 = 结果.body!;
                return new vscode.CompletionList([a, 创建分割符(3), b, ...创建格式化及重新开始项目(4)]);
            }
            case _指令类型_.分部完成: {
                const arg = 指令.参数 as 分部完成参数_;
                if (!arg.项目) {
                    vscode.window.activeTextEditor!.edit(e => {
                        if (!arg.是字面量) {
                            e.replace(new vscode.Range(new vscode.Position(position.line, position.character - 1),
                                new vscode.Position(position.line, position.character)), ",");
                        }
                        else {
                            let 行文本 = document.lineAt(position.line).text.substring(0, position.character);
                            let 最后冒号位置 = 行文本.lastIndexOf(":") + 1;
                            if (最后冒号位置 !== 0) {
                                行文本 = 行文本.substring(最后冒号位置);
                                let 前面空格长度 = 行文本.length - 行文本.trimLeft().length;
                                let 后面空格长度 = 行文本.length - 行文本.trimRight().length;
                                let 前 = 最后冒号位置 + 前面空格长度;
                                let 后 = position.character - 后面空格长度;
                                e.replace(new vscode.Range(new vscode.Position(position.line, 前), new vscode.Position(position.line, 后)), `"${行文本.trim()}",`);
                            }
                        }
                    });
                    return undefined;
                }
                return new vscode.CompletionList(arg.项目);
            }
            case _指令类型_.撤销上次: {
                const 结果 = await this.请求语言服务功能(指令.参数 as NotDictNodeRequestArgs, token);
                if (!结果) {
                    return undefined;
                }
                let a = new 词典完成项目_(vscode.CompletionItemKind.Enum, _词典完成项目种类_.标识符, 结果.body!.text!, 结果.body!.isInString, 1);
                let b = new 词典完成项目_(vscode.CompletionItemKind.Function, _词典完成项目种类_.忽略当前, "撤销: " + 结果.body!.text, undefined, 3, 结果.body!.text);
                return new vscode.CompletionList([a, 创建分割符(2), b]);
            }
            case _指令类型_.请求翻译: {
                const arg = 指令.参数 as 翻译请求参数_;
                const 标识符 = await 翻译标识符({ 原文: arg.文本 });
                let 数组: 词典完成项目_[];
                this.储存的上组项目 = [];
                let iiii = 100;
                let 前缀 = "";
                let 后缀 = "";
                if (!标识符.译文组) {
                    标识符.译文组 = [{ 译文: 标识符.原文, 次数: 1 }];
                }
                if (文本全为大写或下划线(标识符.原文)) {
                    前缀 = "__";
                    后缀 = "__";
                }
                else if (字符是大写(标识符.原文.charCodeAt(0))) {
                    后缀 = "_";
                }
                for (let i = 0; i < 标识符.译文组.length; i++) {
                    let v = 标识符.译文组[i];
                    let a = new 词典完成项目_(vscode.CompletionItemKind.Enum, _词典完成项目种类_.整体词组, v.译文, arg.是字面量, iiii + "", undefined, 前缀, 后缀);
                    (数组! || (数组 = [])).push(a);
                    iiii++;
                }
                if (标识符.组成) {
                    if (前缀) {
                        标识符.组成.unshift({ 原文: 前缀, 译文组: [{ 译文: 前缀, 次数: 1 }] });
                    }
                    if (后缀) {
                        标识符.组成.push({ 原文: 后缀, 译文组: [{ 译文: 后缀, 次数: 1 }] });
                    }
                    let 前一个下划线 = "";
                    (数组! || (数组 = [])).push(创建分割符(iiii));
                    iiii++;
                    for (let ii = 0; ii < 标识符.组成.length; ii++) {
                        let v = 标识符.组成[ii];
                        if (!v.译文组) {
                            v.译文组 = [{ 译文: v.原文, 次数: 1 }];
                        }
                        if (文本全为下划线(v.译文组![0].译文)) {
                            前一个下划线 = v.译文组![0].译文;
                            if (ii === 标识符.组成.length - 1) {
                                let a = new 词典完成项目_(vscode.CompletionItemKind.EnumMember, _词典完成项目种类_.分体词组, 前一个下划线, false, iiii + "");
                                this.储存的上组项目.push([a]);
                                (数组! || (数组 = [])).push(a);
                                前一个下划线 = "";
                                iiii++;
                            }
                        }
                        else {
                            let 临时: 词典完成项目_[] = []
                            for (let iii = 0; iii < v.译文组!.length; iii++) {
                                let a = new 词典完成项目_(vscode.CompletionItemKind.EnumMember, _词典完成项目种类_.分体词组, 前一个下划线 + v.译文组![iii].译文!, false, iiii + "", undefined, undefined, undefined, v);
                                临时.push(a);
                            }
                            if (临时.length) {
                                this.储存的上组项目!.push(临时);
                            }
                            (数组! || (数组 = [])).push(...临时);
                            前一个下划线 = "";
                            iiii++;
                        }
                    }
                }
                if (数组!.length) {
                    return new vscode.CompletionList(数组!);
                }
            }
        }
        return undefined;
    }

    public async 请求语言服务功能(arg: NotDictNodeRequestArgs, token: vscode.CancellationToken) {
        const 结果 = await this.client.execute("getNotDictNode", arg, token);
        if (!结果 || 结果.type !== "response" || !结果.body || 结果.body.isFailure) {
            vscode.commands.executeCommand(格式化词典语句命令_.ID);
            return undefined;
        }
        return 结果;
    }

    public 生成请求参数(context: vscode.CompletionContext, document: vscode.TextDocument, position: vscode.Position) {
        if (context.triggerKind !== vscode.CompletionTriggerKind.TriggerCharacter) return undefined;
        let 行文本 = document.lineAt(position.line);
        if (!行文本.text) return undefined;
        if (!词典语句正则.test(行文本.text)) return undefined;
        const file = this.client.toOpenedFilePath(document);
        if (!file) {
            return undefined;
        }
        let 字符前文本 = 行文本.text.substring(0, position.character);
        // {-                   请求新的标识符,
        // { xxxx:-             请求翻译标识符, 并显示翻译后的词条
        // { xxxx:XX-           可选 有可能是输入部分翻译结果, 输入一个减少一个.
        // { xxxx:XXXX          如果 输入的是整词直接 完成并输出 , 号
        // { xxxx:XXXX-         如果是 分部输出剩余最后一个直接输出 , 号
        // { xxxx:XXXX,-        开始新的标识符请求并回传上一个 xxxx 文本
        const 指令匹配 = 词典头正则.exec(字符前文本);
        let 指令文本 = 指令匹配![1].trimRight();
        let 上个指令 = "";
        if (指令文本.length > 1) {
            for (let i = 指令文本.length - 2; i >= 0; i--) {
                const ch = 指令文本.charAt(i);
                if (ch === "," || ch === "{" || ch === ":") {
                    上个指令 = ch;
                    break;
                }
            }
        }

        if (指令文本.endsWith("{")) {
            return 创建指令(_指令类型_.全新开始, { ...typeConverters.Position.toFileLocationRequestArgs(file, position) });
        }
        else if (指令文本.endsWith(",")) {
            const 内容 = 取分部输出词典原文及译文(指令文本);
            if (内容) {
                vscode.commands.executeCommand(插入词典标识符命令_.ID, { 原文: 内容.原文, 译文组: [{ 译文: 内容.译文, 增加引用: true, 次数: 1 }] });
            }
            return 创建指令(_指令类型_.再次开始, { ...typeConverters.Position.toFileLocationRequestArgs(file, position), ignoreStrings: this.上个请求.text });
        }
        else if (指令文本.endsWith(":")) {
            return 创建指令(_指令类型_.请求翻译, { 文本: this.上个请求.text, 是字面量: this.上个请求.isInString });
        }
        else if (上个指令 && 上个指令 === ":") {
            let index = -1;
            if (this.储存的上组项目 && this.储存的上组项目.length) {
                for (let i = 0; i < this.储存的上组项目.length; i++) {
                    let 临时 = this.储存的上组项目[i];
                    if (临时.indexOf(this.刚输入的完成项目) >= 0) {
                        index = i;
                        break;
                    }
                }
            }
            if (index >= 0) {
                this.储存的上组项目.splice(index, 1);
            }
            if (!this.储存的上组项目 || !this.储存的上组项目.length) {
                let 译文 = 取分部输出词典译文(指令文本);
                if (!this.分部输出内容) {
                    this.分部输出内容 = 译文;
                    译文 = this.分部输出内容;
                }
                else if (译文) {
                    译文 = 删除前缀(译文, this.分部输出内容);
                    this.分部输出内容 = 译文
                }
                if (译文) {
                    vscode.commands.executeCommand(插入词典标识符命令_.ID, { 原文: this.刚输入的完成项目.标识符.原文, 译文组: [{ 译文: 译文, 增加引用: true, 次数: 1 }] });
                }
                return 创建指令(_指令类型_.分部完成, { 是字面量: this.上个请求.isInString });
            }
            const 项目: 词典完成项目_[] = [];
            for (let i = 0; i < this.储存的上组项目.length; i++) {
                项目.push(...this.储存的上组项目[i])
            }
            return 创建指令(_指令类型_.分部完成, { 项目 });
        }
        return undefined;
    }

    public async resolveCompletionItem(
        item: vscode.CompletionItem
    ): Promise<vscode.CompletionItem | undefined> {
        if (item instanceof 词典完成项目_) {
            this.刚输入的完成项目 = item;
        }
        return item;
    }
}

export function register(
    selector: vscode.DocumentSelector,
    modeId: string,
    client: ITypeScriptServiceClient,
    commandManager: CommandManager,
    onCompletionAccepted: (item: vscode.CompletionItem) => void
) {
    return new ConfigurationDependentRegistration(modeId, 'dictSuggest.enabled', () =>
        vscode.languages.registerCompletionItemProvider(selector,
            new CtsScriptDictCompletionItemProvider(client, commandManager, onCompletionAccepted),
            ...CtsScriptDictCompletionItemProvider.triggerCharacters));
}
